//============================================================================
// Name        : cfg.h
// Author      : Yugi
// Version     : 1.0
// Description : 
//============================================================================

#ifndef _CFG_H
#define _CFG_H

#include <stdlib.h>
#include <dr_api.h>

#include "worklist.h"
#include "bitmap.h"

#define DEFAULT_CFG_SIZE	128

/* Structure of basic block node */
typedef struct _BBNODE{
	instrlist_t *basic_block;
	PWORKLIST pList;
	PSBITMAP bitmap;
	bool visited;
} BBNODE, *PBBNODE;

/* Structure of Edge */
typedef struct _EDGE{
	unsigned int src;			// edge source
	unsigned int dst;			// edge destination
	struct _EDGE *next;			// next edge
} EDGE, *PEDGE;

/* Stack for integers */
typedef struct _INT_STACK {
	unsigned int index;
	struct _INT_STACK *previous;
} INT_STACK, *PINT_STACK;

/* Control flow graph */
typedef struct _CFG{
	struct _BBNODE *nodes;		// bb list
	unsigned int size;			// bb list size 
	unsigned int multiple;		// bb list max size = DEFAULT_CFG_SIZE * multiple
	PINT_STACK stack;			// bb stack
	struct _EDGE *head;			// edge list head
	struct _EDGE *tail;			// edge list tail
} CFG, *PCFG;

/* 
* Generate a new control flow gragh.
* 
* RETURN:	new cfg
* NOTES:	Return value should be freed by user
*/
PCFG cfg_new();

/* 
* Insert a basic block to the control flow gragh.
* 
* REQUIRE:	pcfg not NULL
*			pc in text seg
* RETURN:	Index of the target basic block, if the basic block
*			exist, return the existing basic block index
* MODIFY:	pcfg
*/
unsigned int cfg_add_bb(void *drcontext, PCFG pcfg, app_pc pc);

/* 
* Insert an edge to the control flow gragh.
* 
* REQUIRE:	pcfg not NULL
*			src & dst distinguishes, less than pcfg->size
* RETURN:	true if edge added
* MODIFY:	pcfg
*/
bool cfg_add_edge(PCFG pcfg, unsigned int src, unsigned int dst);

/* 
* Static completion. Add branches to pcfg->basic_blocks.
* 
* REQUIRE:	pcfg not NULL
* MODIFY:	pcfg
*/
void cfg_static_completion(void *drcontext, PCFG pcfg);

/* 
* Print control flow gragh
* 
* REQUIRE:	pcfg not NULL
*			outfile not NULL
* NOTE:		if 'content', the instruction will be printed
*/
void cfg_print(void *drcontext, file_t outfile, PCFG pcfg, bool content);

#endif /* End of _CFG_H */